﻿package kliment.geom.color {
	import kliment.math.Calc;
	
	/**
	* ...
	* @author Kliment
	*/
	public class XYZColor  extends ColorAbstract {
		public var rawX:Number = 0;
		public var rawY:Number = 0;
		public var rawZ:Number = 0;
		
		public function XYZColor(host:Color = null) {
			super(host);
		}
		
		public function get x():Number { return (rawX * 1000 + 0.499999 << 0) / 1000 }
		public function get y():Number { return (rawY * 1000 + 0.499999 << 0) / 1000 }
		public function get z():Number { return (rawZ * 1000 + 0.499999 << 0) / 1000 }
		
		public function setValue(x:Number, y:Number, z:Number, update:Boolean = true):void {
			setValue(x, y, z, update);
		}
		
		public function setRawValue(x:Number, y:Number, z:Number, update:Boolean = true):void {
			if (rawX == x && rawY == y && rawZ == z)
				return;
			
			rawX = Calc.inInterval(MIN_RAW, MAX_RAW, x);
			rawY = Calc.inInterval(MIN_RAW, MAX_RAW, y);
			rawZ = Calc.inInterval(MIN_RAW, MAX_RAW, z);
			
			if (color && update)
				color.valueChanged(Color.XYZ);
		}
		
		public function toString():String {
			return "[XYZColor x=" + x + " y=" + y + " z=" + z + "]";
		}
		
		public function clone():XYZColor {
			var result:XYZColor = new XYZColor();
			result.setRawValue(rawX, rawY, rawZ, false);
			return result;
		}
		
		public function toLAB(lab:LABColor = null):LABColor {
			return converToLAB(this, lab);
		}
		
		static public function converToLAB(xyz:XYZColor, lab:LABColor = null):LABColor {
			if (!lab) lab = new LABColor();
			
			var x:Number = xyz.rawX;
			var y:Number = xyz.rawY;
			var z:Number = xyz.rawZ;
			var l:Number = x > .008856 ? (Math.pow(x, 1 / 3)) : (7.787 * x + .1379);
			var a:Number = y > .008856 ? (Math.pow(y, 1 / 3)) : (7.787 * y + .1379);
			var b:Number = z > .008856 ? (Math.pow(z, 1 / 3)) : (7.787 * z + .1379);
			lab.setValue(116 * a - 16, 500 * (l - a), 200 * (a - b), false);
			return lab;
		}
		
		public function toRGB(rgb:RGBColor = null):RGBColor { return converToRGB(this, rgb) }
		static public function converToRGB(xyz:XYZColor, rgb:RGBColor = null):RGBColor {
			if (!rgb) rgb = new RGBColor();
			
			var rawX:Number = xyz.rawX;
			var rawY:Number = xyz.rawY;
			var rawZ:Number = xyz.rawZ;
			rawX = rawX * (95.047 / 100);
			rawZ = rawZ * (108.883 / 100);
			var rawR:Number = 3.24063 * rawX - 1.53721 * rawY - .498629 * rawZ;
			var rawG:Number = -.968931 * rawX + 1.87576 * rawY + .0415175 * rawZ;
			var rawB:Number = 0.0557101 * rawX - .204021 * rawY + 1.057 * rawZ;
			rawR = (rawR > .0031308)?(1.055 * Math.pow(rawR, .4167) - .055):(12.92 * rawR);
			rawG = (rawG > .0031308)?(1.055 * Math.pow(rawG, .4167) - .055):(12.92 * rawG);
			rawB = (rawB > .0031308)?(1.055 * Math.pow(rawB, .4167) - .055):(12.92 * rawB);
			rgb.setRawValue(rawR, rawG, rawB, false);
			
			return rgb;
		}
	}
}
